import axios from 'axios'
import { ElMessage } from 'element-plus' // 补充导入
import { useUserStore } from '@/store/user'
import router from '../router'
import { storeToRefs } from 'pinia'
import { baseUrl } from '@/env.config'
import { isRef } from 'vue'

// 请求配置，建议单独使用文件存储
const reqConfig = {
  untie: true, //拆包配置
  resField: 'data', //返回的响应字段配置
  errCodeMap: {
    400: '请求错误',
    401: '认证失败',
    403: '拒绝访问',
    404: '请求出错',
    408: '请求超时',
    429: '请求频繁, 请稍后再访问',
    500: '服务器开小差啦,请稍后再试~',
    501: '服务未实现',
    502: '网络错误',
    503: '服务不可用',
    504: '网络超时',
    505: 'HTTP版本不受支持',
    default: '系统未知错误',
  }, //错误码映射
  race: true, //竞态配置
  tokenField: 'Authorization', //token字段
}
const reqMap = new Map()
// 创建请求实例
const service = axios.create({
  baseURL: baseUrl,
  timeout: 60000,
})

// token刷新管理
class TokenRefreshManager {
  constructor() {
    this.isRefreshing = false;
    this.waitingRequests = new Map();
  }
  addWaitingRequest(key, callback) {
    if (!this.waitingRequests.has(key)) {
      this.waitingRequests.set(key, []);
    }
    this.waitingRequests.get(key).push(callback);
  }
  executeWaitingRequests() {
    this.waitingRequests.forEach(callbacks => {
      callbacks.forEach(cb => cb());
    });
    this.clearWaitingRequests();
  }
  clearWaitingRequests() {
    this.waitingRequests.clear();
  }
  setRefreshing(status) {
    this.isRefreshing = status;
  }
  isTokenRefreshing() {
    return this.isRefreshing;
  }
}
const tokenRefreshManager = new TokenRefreshManager();

// 请求前置拦截
service.interceptors.request.use(async (config) => {
  // 获取竞态配置
  const { race = reqConfig.race } = config
  if (race) {
    const reqKey = getReqKey(config)
    // 有重复的请求则取消之前的请求
    if (reqMap.has(reqKey)) {
      reqMap.get(reqKey)?.abort();
      reqMap.delete(reqKey);
    } else {
      const controller = new AbortController();
      config.signal = controller.signal;
      reqMap.set(reqKey, controller)
    }
  }
  // 获取token
  const { token } = storeToRefs(useUserStore())
  // 获取相关属性配置
  const { loading, noToken } = config
  // 判断接口是否需要token
  if (!noToken) {
    if (!token.value) {
      ElMessage.error('登录失效，请重新登录！')
      // 可以做一些退出登录操作并且跳到登录页面
      return router.push('/login')
    }
    config.headers[reqConfig.tokenField] = token.value
  }
  // 启动loading
  isRef(loading) && (loading.value = true)
  return config
})

//请求后处理
service.interceptors.response.use(async (res) => {
  const { status, statusText, data: resData, config } = res
  const { untie = reqConfig.untie, loading, resField = reqConfig.resField, race = reqConfig.race } = config
  // loading停止
  isRef(loading) && (loading.value = false)
  // 判断竞态状态
  if (race) {
    const reqKey = getReqKey(config)
    reqMap.delete(reqKey);
  }
  // 如果status不等于200，相当于axios的请求都没走通，则直接返回错误信息
  if (status !== 200) {
    ElMessage.error(statusText)
    return Promise.reject(res)
  } else {
    // 等于200则进行业务状态码的判断
    let { code, msg } = resData
    msg = msg || reqConfig.errCodeMap[code] || reqConfig.errCodeMap['default']
    // 首先判断是否拆包
    if (untie) {
      if (code === 200) {
        return Promise.resolve(resData[resField])
      } else if (code === 401) {
        // 做一些退出登录或者跳到登录页的操作或者进行token刷新
        if (tokenRefreshManager.isTokenRefreshing()) {
          const reqKey = getReqKey(config);
          return new Promise((resolve, reject) => {
            tokenRefreshManager.addWaitingRequest(reqKey, () => {
              service(config).then(resolve).catch(reject);
            });
          });
        }
        const { token } = storeToRefs(useUserStore())
        // 如果连失效token都没有，则跳转到登录
        if (!token.value) {
          ElMessage.error('请先登录！')
          return router.push('/login')
        }
        tokenRefreshManager.setRefreshing(true)
        // 刷新token
        apiRefreshToken().then(() => {
          tokenRefreshManager.executeWaitingRequests();
        }).catch(err => {
          tokenRefreshManager.clearWaitingRequests();
          router.push('/login');
        }).finally(() => {
          // 结束刷新
          tokenRefreshManager.setRefreshing(false);
        })
      } else {
        ElMessage.error(msg)
        return Promise.reject(resData)
      }
    } else {
      // 不拆包则需要自己出来状态码以及错误信息
      return Promise.resolve(resData)
    }
  }
}, err => {
  const { message, config } = err
  const { loading, untie, race = reqConfig.race } = config
  isRef(loading) && (loading.value = false)
  if (race) {
    const reqKey = getReqKey(config)
    reqMap.delete(reqKey);
  }
  // 如果是拆包则提示，如果不是则直接返回让他自己处理错误信息
  if (untie) {
    ElMessage.error(message)
  } else {
    return Promise.reject(err)
  }
})

export default service

const getReqKey = (config) => {
  const path = config.url?.split('?')?.[0];
  return `${config.method?.toUpperCase()}:${path}`
}
// token刷新的方法
const apiRefreshToken = () => {
  // request 模拟请求方法
}

